using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
using System.Reflection;

namespace Rotempco.Core.Logic
{
    internal class GenericClonerLogic
    {
        internal static TDestination Clone<TSource, TDestination>(TSource instance, TDestination destination, List<Expression<Func<TSource, object>>> ignoreSourcePropertyMemberList, bool softClone) where TDestination : new()
        {
            List<string> ignorePropertyNameList = new List<string>();
            if (ignoreSourcePropertyMemberList != null && ignoreSourcePropertyMemberList.Count() > 0)
            {
                foreach (Expression<Func<TSource, Object>> ignoreSourceProperty in ignoreSourcePropertyMemberList)
                {
                    ignorePropertyNameList.Add(GetPropertyName(ignoreSourceProperty));
                }
            }

            Type destinationType = destination.GetType();
            PropertyInfo[] sourceFields = instance.GetType().GetProperties();

            foreach (PropertyInfo sourceField in sourceFields)
            {
                if (ignorePropertyNameList.Count() > 0 && ignorePropertyNameList.Contains(sourceField.Name))
                    continue;

                PropertyInfo destinationField = destinationType.GetProperty(sourceField.Name);
                if (softClone == true && destinationField == null)
                    continue;

                object value = sourceField.GetValue(instance, null);

                destinationField.SetValue(destination, value, null);
            }

            return destination;
        }

        internal static TDestination Clone<TSource, TDestination>(TSource instance, List<Expression<Func<TSource, object>>> ignoreSourcePropertyMemberList, bool softClone) where TDestination : new()
        {
            TDestination destination = new TDestination();
            return Clone<TSource, TDestination>(instance, destination, ignoreSourcePropertyMemberList, softClone);
        }

        internal static string GetPropertyName<T, TReturn>(Expression<Func<T, TReturn>> expression)
        {
            LambdaExpression lambda = expression as LambdaExpression;

            MemberExpression memberExpression = null;
            if (lambda.Body.NodeType == ExpressionType.Convert)
                memberExpression = ((UnaryExpression)lambda.Body).Operand as MemberExpression;
            else if (lambda.Body.NodeType == ExpressionType.MemberAccess)
                memberExpression = lambda.Body as MemberExpression;

            return memberExpression.Member.Name;
        }

    }
}
